<?php


namespace App\Service;

use EchoPHP\Facades\Log;
use GuzzleHttp\Exception\RequestException;
use InvalidArgumentException;
use Exception;
use GuzzleHttp\Client;

class Sms {

    protected $baseUri;

    protected $errorMsg;

    public function __construct() {
        $this->baseUri = config('app.sms.baseUri');
        if (!$this->baseUri) {
            throw new InvalidArgumentException('短信接口地址未定义');
        }
    }

    /**
     * 发送短信
     * @param array|string $mobilePhone 手机号,多个手机支持数字格式或者逗号分割
     * @param $content
     * @param $channel 发送渠道号
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function send($mobilePhone, $content, $channel) {
        try {
            $mobilePhone = trim($mobilePhone);
            $content = trim($content);

            if (empty($mobilePhone) || empty($content)) {
                return false;
            }

            if (is_array($mobilePhone)) {
                $mobilePhone = implode(',', $mobilePhone);
            }
            $channels = config('app.sms.channel', []);
            if (!in_array($channel, $channels)) {
                throw new InvalidArgumentException('短信通道[' . $channel . ']未定义');
            }

            //将html标签换行转换为 \r\n便于阅读显示时好看
            $content = preg_replace('/<br[\s\/]*>/i', "\r\n", $content);
            $params = [
                'systemType' => $channel,
                'mobileNum' => $mobilePhone,
                'keyNum' => '',
                'msgType' => '0',
                'content' => $content,
                'customer' => '',
            ];

            $client = new Client([
                'base_uri' => $this->baseUri,
                'timeout' => 2
            ]);


            $response = $client->request('POST', 'SendSms', [
                'form_params' => $params
            ]);
            $content = $response->getBody()->getContents();
            if (!$contentXml = simplexml_load_string($content)) {
                $this->errorMsg = '接口返回XML文件解析失败:' . $content;
                Log::error($this->errorMsg, $params);
                return false;
            }
            $content = json_decode(json_encode($contentXml), true);
            $content['SendResult'] = $content['SendResult'] ?? [];
            if (strpos($mobilePhone, ',') === false) {
                $content['SendResult'] = [$content['SendResult']];
            }
            $errors = [];
            foreach ($content['SendResult'] as $item) {
                $mobilePhone = $item['MobileNum'] ?? '';
                if (empty($mobilePhone)) {
                    continue;
                }
                $errorNo = $item['ErrorNo'] ?? -1;
                if ($errorNo != 0) {
                    $errorMsg = $item['ErrorMsg'] ?? '';
                    $this->errorMsg .= $mobilePhone . ':[' . $errorMsg . '];';
                    $errors[$mobilePhone] = $errorMsg;
                }
            }
            if (!empty($errors)) {
                Log::error('短信发送失败', array_merge($params, $errors));
                return false;
            }
            return true;
        } catch (RequestException $e) {
            if ($e->hasResponse()) {
                $this->errorMsg = $e->getResponse()->getBody()->getContents();
            } else {
                $this->errorMsg = $e->getMessage();
            }
            Log::error($this->errorMsg, $params);
            return false;
        } catch (Exception $e) {
            $this->errorMsg = $e->getMessage();
            Log::error($this->errorMsg, $params);
            return false;
        }
    }

    /**
     * 发送国际短信
     * @param string $sign 国际区号  886
     * @param string $mobileNum 手机号码  12345678
     * @param $content
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function sendOneWithSign($sign, $mobileNum, $content) {
        try {
            $sign = trim($sign);
            $mobileNum = trim($mobileNum);
            $content = trim($content);

            if (empty($sign) || empty($mobileNum) || empty($mobileNum)) {
                return false;
            }

            $channel = config('app.sms.channel.international');;

            //将html标签换行转换为 \r\n便于阅读显示时好看
            $content = preg_replace('/<br[\s\/]*>/i', "\r\n", $content);
            $params = [
                'systemType' => $channel,
                'mobileNum' => $mobileNum,
                'keyNum' => '',
                'msgType' => '0',
                'content' => $content,
                'sign' => $sign,
                'customer' => '',
            ];

            $client = new Client([
                'base_uri' => $this->baseUri,
                'timeout' => 2
            ]);


            $response = $client->request('POST', 'SendSms_WithSign', [
                'form_params' => $params
            ]);
            $content = $response->getBody()->getContents();
            if (!$contentXml = simplexml_load_string($content)) {
                $this->errorMsg = '接口返回XML文件解析失败:' . $content;
                Log::error($this->errorMsg, $params);
                return false;
            }
            $content = json_decode(json_encode($contentXml), true);
            $content['SendResult'] = $content['SendResult'] ?? [];
            if (strpos($mobileNum, ',') === false) {
                $content['SendResult'] = [$content['SendResult']];
            }
            $errors = [];
            foreach ($content['SendResult'] as $item) {
                $mobilePhone = $item['MobileNum'] ?? '';
                if (empty($mobilePhone)) {
                    continue;
                }
                $errorNo = $item['ErrorNo'] ?? -1;
                if ($errorNo != 0) {
                    $errorMsg = $item['ErrorMsg'] ?? '';
                    $this->errorMsg .= $mobilePhone . ':[' . $errorMsg . '];';
                    $errors[$mobilePhone] = $errorMsg;
                }
            }
            if (!empty($errors)) {
                Log::error('短信发送失败', array_merge($params, $errors));
                return false;
            }
            return true;
        } catch (RequestException $e) {
            if ($e->hasResponse()) {
                $this->errorMsg = $e->getResponse()->getBody()->getContents();
            } else {
                $this->errorMsg = $e->getMessage();
            }
            Log::error($this->errorMsg, $params);
            return false;
        } catch (Exception $e) {
            $this->errorMsg = $e->getMessage();
            Log::error($this->errorMsg, $params);
            return false;
        }
    }


    /**发送单条短信
     * @param $mobilePhone 13601750981或+886-12345678
     * @param $content
     * @param $channel
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function sendOne($mobilePhone, $content, $channel) {
        if (empty($mobilePhone)) {
            return false;
        }
        $phoneArr = explode("-", $mobilePhone);

        if (count($phoneArr) == 1) {
            return $this->send($mobilePhone, $content, $channel);
        }

        if (count($phoneArr) > 2 || empty($phoneArr[1])) {
            return false;
        }

        $sign = empty($phoneArr[0]) ? '86' : ltrim(trim($phoneArr[0], '+'), '0');
        $mobileNum = trim($phoneArr[1]);
        if ($sign == '86') {
            return $this->send($mobileNum, $content, $channel);
        }
        return $this->sendOneWithSign($sign, $mobileNum, $content);
    }

    /**
     * 获取发送错误提示
     * @return mixed
     */
    public function getMessage() {
        return $this->errorMsg;
    }
}